//////////////////////////////////////////////
// Matrix.js
//
//////////////////////////////////////////////

/// Class ------------------------------------
	
nkMathsTests.Matrix = class Matrix extends nkDebug.TestClass
{
	// Statics
	static instance = new Matrix ("nkMathsTests.Matrix") ;

	// Utils
	testVectorEquality (a, b, epsilon, message = "Vectors not equal")
	{
		nkDebug.TestUtils.areNumbersEqual(a._x, b._x, epsilon, message) ;
		nkDebug.TestUtils.areNumbersEqual(a._y, b._y, epsilon, message) ;
		nkDebug.TestUtils.areNumbersEqual(a._z, b._z, epsilon, message) ;
		nkDebug.TestUtils.areNumbersEqual(a._w, b._w, epsilon, message) ;
	}

	testMatrixEquality (a, b, epsilon, message = "Matrices not equal")
	{
		for (let i = 0 ; i < 4 ; ++i)
		{
			for (let j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(a._m[i][j], b._m[i][j], epsilon, message) ;
		}
	}

	getVectorConstructor (managed)
	{
		return managed ? nkMaths.Vector : nkMaths.unmanaged.Vector ;
	}

	getQuaternionConstructor (managed)
	{
		return managed ? nkMaths.Quaternion : nkMaths.unmanaged.Quaternion ;
	}

	getMatrixConstructor (managed)
	{
		return managed ? nkMaths.Matrix : nkMaths.unmanaged.Matrix ;
	}

	// Constructors
	testDefaultConstructor (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;

		nkDebug.TestUtils.areNumbersEqual(m._m[0][0], 1, 0, "Wrong [0][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[0][1], 0, 0, "Wrong [0][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[0][2], 0, 0, "Wrong [0][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[0][3], 0, 0, "Wrong [0][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m._m[1][0], 0, 0, "Wrong [1][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[1][1], 1, 0, "Wrong [1][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[1][2], 0, 0, "Wrong [1][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[1][3], 0, 0, "Wrong [1][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m._m[2][0], 0, 0, "Wrong [2][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[2][1], 0, 0, "Wrong [2][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[2][2], 1, 0, "Wrong [2][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[2][3], 0, 0, "Wrong [2][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m._m[3][0], 0, 0, "Wrong [3][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[3][1], 0, 0, "Wrong [3][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[3][2], 0, 0, "Wrong [3][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m._m[3][3], 1, 0, "Wrong [3][3]") ;

		if (!managed)
			m.delete() ;
	}

	testArgsConstructor (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;

		const m2 = new ctor (2, 3, 4, 5) ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[0][0], 2, 0, "Wrong [0][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[0][1], 3, 0, "Wrong [0][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[0][2], 0, 0, "Wrong [0][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[0][3], 0, 0, "Wrong [0][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m2._m[1][0], 4, 0, "Wrong [1][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[1][1], 5, 0, "Wrong [1][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[1][2], 0, 0, "Wrong [1][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[1][3], 0, 0, "Wrong [1][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m2._m[2][0], 0, 0, "Wrong [2][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[2][1], 0, 0, "Wrong [2][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[2][2], 1, 0, "Wrong [2][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[2][3], 0, 0, "Wrong [2][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m2._m[3][0], 0, 0, "Wrong [3][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[3][1], 0, 0, "Wrong [3][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[3][2], 0, 0, "Wrong [3][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m2._m[3][3], 1, 0, "Wrong [3][3]") ;

		const m3 = new ctor (2, 3, 4, 5, 6, 7, 8, 9, 10) ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[0][0], 2, 0, "Wrong [0][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[0][1], 3, 0, "Wrong [0][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[0][2], 4, 0, "Wrong [0][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[0][3], 0, 0, "Wrong [0][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m3._m[1][0], 5, 0, "Wrong [1][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[1][1], 6, 0, "Wrong [1][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[1][2], 7, 0, "Wrong [1][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[1][3], 0, 0, "Wrong [1][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m3._m[2][0], 8, 0, "Wrong [2][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[2][1], 9, 0, "Wrong [2][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[2][2], 10, 0, "Wrong [2][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[2][3], 0, 0, "Wrong [2][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m3._m[3][0], 0, 0, "Wrong [3][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[3][1], 0, 0, "Wrong [3][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[3][2], 0, 0, "Wrong [3][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m3._m[3][3], 1, 0, "Wrong [3][3]") ;

		const m4 = new ctor (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[0][0], 2, 0, "Wrong [0][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[0][1], 3, 0, "Wrong [0][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[0][2], 4, 0, "Wrong [0][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[0][3], 5, 0, "Wrong [0][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m4._m[1][0], 6, 0, "Wrong [1][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[1][1], 7, 0, "Wrong [1][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[1][2], 8, 0, "Wrong [1][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[1][3], 9, 0, "Wrong [1][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m4._m[2][0], 10, 0, "Wrong [2][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[2][1], 11, 0, "Wrong [2][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[2][2], 12, 0, "Wrong [2][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[2][3], 13, 0, "Wrong [2][3]") ;

		nkDebug.TestUtils.areNumbersEqual(m4._m[3][0], 14, 0, "Wrong [3][0]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[3][1], 15, 0, "Wrong [3][1]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[3][2], 16, 0, "Wrong [3][2]") ;
		nkDebug.TestUtils.areNumbersEqual(m4._m[3][3], 17, 0, "Wrong [3][3]") ;

		if (!managed)
		{
			m2.delete() ;
			m3.delete() ;
			m4.delete() ;
		}
	}

	testCopyConstructor (managed, managedC)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const ctorC = Matrix.instance.getMatrixConstructor(managedC) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const b = new ctorC (a) ;

		nkDebug.TestUtils.check(a.equals(b), "Copy incorrect") ;

		if (!managed)
			a.delete() ;

		if (!managedC)
			b.delete() ;
	}

	// Getters
	testGetRow0 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (1, 2, 3, 4) ;

		const rm = a.getRow0() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getRow0_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetRow1 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (5, 6, 7, 8) ;

		const rm = a.getRow1() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getRow1_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetRow2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (9, 10, 11, 12) ;

		const rm = a.getRow2() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getRow2_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetRow3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (13, 14, 15, 16) ;

		const rm = a.getRow3() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getRow3_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetCol0 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (1, 5, 9, 13) ;

		const rm = a.getCol0() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getCol0_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetCol1 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (2, 6, 10, 14) ;

		const rm = a.getCol1() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getCol1_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetCol2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (3, 7, 11, 15) ;

		const rm = a.getCol2() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getCol2_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	testGetCol3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Vector (4, 8, 12, 16) ;

		const rm = a.getCol3() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not an instance of managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed row values") ;

		const ru = a.getCol3_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an instance of unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged row values") ;
		ru.delete() ;

		if (!managed)
			a.delete() ;
	}

	// Alterations
	testGetInverseMat2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 2, 6) ;
		const ref = new nkMaths.Matrix (0.6, -0.7, -0.2, 0.4) ;

		const rm = m.getInverseMat2() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Matrix, "Not an instance of managed vector") ;
		this.testMatrixEquality(rm, ref, 0.00001, "Bad managed result") ;

		const ru = m.getInverseMat2_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Matrix, "Not an instance of unmanaged vector") ;
		this.testMatrixEquality(ru, ref, 0.00001, "Bad unmanaged result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testGetInverseMat3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 5, 2, 6, 2, 1, 3, 3) ;
		const ref = new nkMaths.Matrix (0.6, -0.3, -0.8, -0.2, 0.35, 0.1, 0, -0.25, 0.5) ;

		const rm = m.getInverseMat3() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Matrix, "Not an instance of managed vector") ;
		this.testMatrixEquality(rm, ref, 0.00001, "Bad managed result") ;

		const ru = m.getInverseMat3_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Matrix, "Not an instance of unmanaged vector") ;
		this.testMatrixEquality(ru, ref, 0.00001, "Bad unmanaged result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testGetInverseMat4 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 5, 6, 2, 6, 2, 5, 1, 3, 3, 4, 3, 1, 3, 1) ;
		const ref = new nkMaths.Matrix
			(
				-1, 1, 0, 1,
				1.1818181818181819, -0.7727272727272727, -0.5909090909090909, -0.8636363636363636,
				1.0909090909090908, -1.1363636363636365, -0.045454545454545456, -0.6818181818181818,
				-1.4545454545454546, 1.1818181818181819, 0.7272727272727273, 0.9090909090909091
			) ;

		const rm = m.getInverseMat4() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Matrix, "Not an instance of managed vector") ;
		this.testMatrixEquality(rm, ref, 0.00001, "Bad managed result") ;

		const ru = m.getInverseMat4_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Matrix, "Not an instance of unmanaged vector") ;
		this.testMatrixEquality(ru, ref, 0.00001, "Bad unmanaged result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testGetTranspose (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Matrix (1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16) ;

		const rm = m.getTranspose() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Matrix, "Not an instance of managed vector") ;
		this.testMatrixEquality(rm, ref, 0.00001, "Bad managed result") ;

		const ru = m.getTranspose_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Matrix, "Not an instance of unmanaged vector") ;
		this.testMatrixEquality(ru, ref, 0.00001, "Bad unmanaged result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testInverseMat2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 2, 6) ;
		const ref = new nkMaths.Matrix (0.6, -0.7, -0.2, 0.4) ;

		m.inverseMat2() ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad result") ;

		if (!managed)
			m.delete() ;
	}

	testInverseMat3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 5, 2, 6, 2, 1, 3, 3) ;
		const ref = new nkMaths.Matrix (0.6, -0.3, -0.8, -0.2, 0.35, 0.1, 0, -0.25, 0.5) ;

		m.inverseMat3() ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad managed result") ;

		if (!managed)
			m.delete() ;
	}

	testInverseMat4 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 7, 5, 6, 2, 6, 2, 5, 1, 3, 3, 4, 3, 1, 3, 1) ;
		const ref = new nkMaths.Matrix
			(
				-1, 1, 0, 1,
				1.1818181818181819, -0.7727272727272727, -0.5909090909090909, -0.8636363636363636,
				1.0909090909090908, -1.1363636363636365, -0.045454545454545456, -0.6818181818181818,
				-1.4545454545454546, 1.1818181818181819, 0.7272727272727273, 0.9090909090909091
			) ;

		m.inverseMat4() ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad managed result") ;

		if (!managed)
			m.delete() ;
	}

	testTranspose (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const ref = new nkMaths.Matrix (1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16) ;

		m.transpose() ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad managed result") ;

		if (!managed)
			m.delete() ;
	}

	// Transformations
	testGetPositionComponent (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (1, 0, 0, 3, 0, 1, 0, 5, 0, 0, 1, 2, 0, 0, 0, 1) ;
		const ref = new nkMaths.Vector (3, 5, 2) ;

		const rm = m.getPositionComponent() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not a managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed result") ;

		const ru = m.getPositionComponent_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad unmanaged result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testGetOrientationComponent (managed)
	{
		const radians90 = 90 * nkMaths.MathConstants.PI / 180 ;
		const cos90 = Math.cos(radians90) ;
		const sin90 = Math.sin(radians90) ;

		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (1, 0, 0, 1, 0, 2 * cos90, -sin90, 1, 0, sin90, 2 * cos90, 1, 0, 0, 0, 1) ;
		const ref = new nkMaths.Matrix (1, 0, 0, 0, 0, cos90, -sin90, 0, 0, sin90, cos90, 0, 0, 0, 0, 1) ;

		const rm = m.getOrientationComponent() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Matrix, "Not a managed matrix") ;
		this.testMatrixEquality(rm, ref, 0.00001, "Bad managed result") ;

		const ru = m.getOrientationComponent_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Matrix, "Not an unmanaged matrix") ;
		this.testMatrixEquality(ru, ref, 0.00001, "Bad managed result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testGetScaleComponent (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1) ;
		const ref = new nkMaths.Vector (4, 2, 3) ;

		const rm = m.getScaleComponent() ;
		nkDebug.TestUtils.check(rm instanceof nkMaths.Vector, "Not a managed vector") ;
		nkDebug.TestUtils.check(rm.equals(ref), "Bad managed result") ;

		const ru = m.getScaleComponent_u() ;
		nkDebug.TestUtils.check(ru instanceof nkMaths.unmanaged.Vector, "Not an unmanaged vector") ;
		nkDebug.TestUtils.check(ru.equals(ref), "Bad managed result") ;
		ru.delete() ;

		if (!managed)
			m.delete() ;
	}

	testSetToViewMatrixDirection (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;
		m.setToViewMatrixDirection(new nkMaths.Vector (0, 1, 0), new nkMaths.Vector (0, 0, 1), new nkMaths.Vector (0, 1, 0)) ;

		const ref = new nkMaths.Matrix (1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 1) ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad result") ;
	}

	testSetToPerspectiveMatrix (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;
		m.setToPerspectiveMatrix(nkMaths.MathConstants.PI_OVER_2, 21 / 9, 0.1, 100) ;

		const ref = new nkMaths.Matrix (0.428571433, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1.00100100, -0.100100100, 0, 0, 1, 0) ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad result") ;
	}

	testSetToOrthographicMatrix (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;
		m.setToOrthographicMatrix(170, 190, 0.1, 100) ;

		const ref = new nkMaths.Matrix (0.0117647061, 0, 0, 0, 0, 0.0105263162, 0, 0, 0, 0, 0.0100100096, -0.00100100099, 0, 0, 0, 1) ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad result") ;
	}

	testSetPositionComponent (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;

		const ref = new nkMaths.Vector (1, 2, 3) ;
		m.setPositionComponent(ref) ;
		nkDebug.TestUtils.check(m.getPositionComponent().equals(ref), "Bad component") ;

		if (!managed)
			m.delete() ;
	}

	testSetOrientationComponent (managed)
	{
		const radians90 = 90 * nkMaths.MathConstants.PI / 180 ;
		const cos90 = Math.cos(radians90) ;
		const sin90 = Math.sin(radians90) ;
		const ref = new nkMaths.Matrix (1, 0, 0, 0, 0, cos90, -sin90, 0, 0, sin90, cos90, 0, 0, 0, 0, 1) ;

		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;
		m.setOrientationComponent(new nkMaths.Quaternion (0.707106769, 0, 0, 0.707106769)) ;
		this.testMatrixEquality(m, ref, 0.00001, "Bad result") ;

		if (!managed)
			m.delete() ;
	}

	testSetScaleComponent (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;

		const ref = new nkMaths.Vector (1, 2, 3) ;
		m.setScaleComponent(ref) ;
		nkDebug.TestUtils.check(m.getScaleComponent().equals(ref), "Bad component") ;

		if (!managed)
			m.delete() ;
	}

	testSetToTransformation (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor () ;

		const pos = new nkMaths.Vector (1, 3, 4) ;
		const rot = new nkMaths.Quaternion (0.707106769, 0, 0, 0.707106769) ;
		const scale = new nkMaths.Vector (2, 3, 4) ;
		
		const radians90 = 90 * nkMaths.MathConstants.PI / 180 ;
		const cos90 = Math.cos(radians90) ;
		const sin90 = Math.sin(radians90) ;
		const rotMat = new nkMaths.Matrix (1, 0, 0, 0, 0, cos90, -sin90, 0, 0, sin90, cos90, 0, 0, 0, 0, 1) ;

		
		m.setToTransformation(pos, rot, scale) ;
		nkDebug.TestUtils.check(m.getPositionComponent().equals(pos), "Bad position") ;
		this.testMatrixEquality(m.getOrientationComponent(), rotMat, 0.00001, "Bad orientation") ;
		this.testVectorEquality(m.getScaleComponent(), scale, 0.000001, "Bad scale") ;

		if (!managed)
			m.delete() ;
	}

	// Utilities
	testDeterminantMat2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1) ;
		const b = new ctor (1, 0, 0, 5) ;

		nkDebug.TestUtils.areNumbersEqual(a.getDeterminantMat2(), 1, 0, "Bad determinant 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getDeterminantMat2(), 5, 0, "Bad determinant 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	testDeterminantMat3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 0, 1, 0, 0, 5, 1) ;
		const b = new ctor (1, -2, 4, -5, 2, 0, 1, 0, 3) ;

		nkDebug.TestUtils.areNumbersEqual(a.getDeterminantMat3(), 1, 0, "Bad determinant 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getDeterminantMat3(), -32, 0, "Bad determinant 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	testDeterminantMat4 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor (4, 3, 2, 2, 0, 1, -3, 3, 0, -1, 3, 3, 0, 3, 1, 1) ;

		nkDebug.TestUtils.areNumbersEqual(a.getDeterminantMat4(), 1, 0, "Bad determinant 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getDeterminantMat4(), -240, 0, "Bad determinant 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	testTraceMat2 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor (1, 0, 0, 1, 0, 5, 0, 2, 0, 5, 2, 3, 0, 0, 0, 2) ;

		nkDebug.TestUtils.areNumbersEqual(a.getTraceMat2(), 2, 0, "Bad trace 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getTraceMat2(), 6, 0, "Bad trace 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	testTraceMat3 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor (1, 0, 0, 1, 0, 5, 0, 2, 0, 5, 2, 3, 0, 0, 0, 2) ;

		nkDebug.TestUtils.areNumbersEqual(a.getTraceMat3(), 3, 0, "Bad trace 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getTraceMat3(), 8, 0, "Bad trace 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	testTraceMat4 (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor (1, 0, 0, 1, 0, 5, 0, 2, 0, 5, 2, 3, 0, 0, 0, 2) ;

		nkDebug.TestUtils.areNumbersEqual(a.getTraceMat4(), 4, 0, "Bad trace 0") ;
		nkDebug.TestUtils.areNumbersEqual(b.getTraceMat4(), 10, 0, "Bad trace 1") ;

		if (!managed)
		{
			a.delete() ;
			b.delete() ;
		}
	}

	// Operators
	testEqualsOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getMatrixConstructor(managed1) ;
		const a = new ctor0 (5, 2, 6, 4) ;
		const b = new ctor1 (14, 30, 1, 2, 6, 8, 1, 2, 3, 14, 15, 2, 36, 4, 8, 9) ;
		const c = new ctor1 (14, 30, 1, 2, 6, 8, 1, 2, 3, 14, 15, 2, 36, 4, 8, 9) ;

		nkDebug.TestUtils.check(a.equals(a), "Incorrect equal result") ;
		nkDebug.TestUtils.check(!a.equals(b), "Incorrect equal result") ;
		nkDebug.TestUtils.check(!b.equals(a), "Incorrect equal result") ;
		nkDebug.TestUtils.check(!a.equals(c), "Incorrect equal result") ;
		nkDebug.TestUtils.check(!c.equals(a), "Incorrect equal result") ;
		nkDebug.TestUtils.check(b.equals(b), "Incorrect equal result") ;
		nkDebug.TestUtils.check(c.equals(b), "Incorrect equal result") ;
		nkDebug.TestUtils.check(b.equals(c), "Incorrect equal result") ;

		if (!managed0)
			a.delete() ;

		if (!managed1)
		{
			b.delete() ;
			c.delete() ;
		}
	}

	testAssignOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getMatrixConstructor(managed1) ;
		const q0 = new ctor0 (2, 3, 4, 5) ;
		const q1 = new ctor1 (5, 4, 3, 2) ;

		q0.assign(q1) ;
		nkDebug.TestUtils.check(q0.equals(q1)) ;

		if (!managed0)
			q0.delete() ;

		if (!managed1)
			q1.delete() ;
	}

	testCloneOperator (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const m = new ctor (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;

		const cm = m.clone() ;
		nkDebug.TestUtils.check(cm.equals(m), "Clone incorrect") ;
		nkDebug.TestUtils.check(cm instanceof nkMaths.Matrix, "Not right managed class") ;

		const cu = m.clone_u() ;
		nkDebug.TestUtils.check(cu.equals(m), "Clone incorrect") ;
		nkDebug.TestUtils.check(cu instanceof nkMaths.unmanaged.Matrix, "Not right unmanaged class") ;
		cu.delete() ;

		if (!managed)
			m.delete() ;
	}

	testAddOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getMatrixConstructor(managed1) ;
		const a = new ctor0 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const b = new ctor1 (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) ;

		const ab = a.add(b) ;

		for (var i = 0 ; i < 4 ; ++i)
		{
			for (var j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(ab._m[i][j], a._m[i][j] + b._m[i][j], 0, "Incorrect addition") ;
		}

		if (!managed0)
			a.delete() ;

		if (!managed1)
			b.delete() ;
	}

	testAddOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = new nkMaths.Matrix () ;

		const rManaged = a.add(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.add_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testSubOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getMatrixConstructor(managed1) ;
		const a = new ctor0 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ;
		const b = new ctor1 (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) ;

		const ab = a.sub(b) ;

		for (var i = 0 ; i < 4 ; ++i)
		{
			for (var j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(ab._m[i][j], a._m[i][j] - b._m[i][j], 0, "Incorrect sub") ;
		}

		if (!managed0)
			a.delete() ;

		if (!managed1)
			b.delete() ;
	}

	testSubOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = new nkMaths.Matrix () ;

		const rManaged = a.sub(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.sub_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testMulOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getMatrixConstructor(managed1) ;
		const a = new ctor0 (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor1 (1, 0, 0, 1, 0, 5, 0, 2, 0, 5, 2, 3, 0, 0, 1, 2) ;

		const ref = new nkMaths.Matrix (1, 0, 1, 3, 0, 5, 2, 6, 0, 30, 5, 19, 0, 0, 1, 2) ;
		const ab = a.mul(b) ;

		for (var i = 0 ; i < 4 ; ++i)
		{
			for (var j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(ab._m[i][j], ref._m[i][j], 0, "Incorrect mul") ;
		}

		if (!managed0)
			a.delete() ;

		if (!managed1)
			b.delete() ;
	}

	testMulOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = new nkMaths.Matrix () ;

		const rManaged = a.mul(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.mul_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testMulVectorOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getVectorConstructor(managed1) ;
		const a = new ctor0 (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = new ctor1 (1, 1, 1, 1) ;

		const ref = new nkMaths.Vector (2, 3, 9, 1) ;
		const ab = a.mulVector(b) ;
		nkDebug.TestUtils.check(ab.equals(ref), "Bad transformation") ;

		if (!managed0)
			a.delete() ;

		if (!managed1)
			b.delete() ;
	}

	testMulVectorOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = new nkMaths.Vector () ;

		const rManaged = a.mulVector(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.mulVector_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testMulQuaternionOperator (managed0, managed1)
	{
		const ctor0 = Matrix.instance.getMatrixConstructor(managed0) ;
		const ctor1 = Matrix.instance.getQuaternionConstructor(managed1) ;
		const qx = new ctor1 (0.707106769, 0, 0, 0.707106769) ;
		const qy = new ctor1 (0, 0.707106769, 0, 0.707106769) ;
		const m = new ctor0 () ;
		m.setOrientationComponent(qx) ;

		const ref = new nkMaths.Quaternion (0.499999970, 0.499999970, 0.499999970, 0.499999970) ;
		const qxy = m.mulQuaternion(qy) ;
		nkDebug.TestUtils.areNumbersEqual(qxy._x, ref._x, 0.00001, "Bad transformation") ;
		nkDebug.TestUtils.areNumbersEqual(qxy._y, ref._y, 0.00001, "Bad transformation") ;
		nkDebug.TestUtils.areNumbersEqual(qxy._z, ref._z, 0.00001, "Bad transformation") ;
		nkDebug.TestUtils.areNumbersEqual(qxy._w, ref._w, 0.00001, "Bad transformation") ;

		if (!managed0)
			m.delete() ;

		if (!managed1)
		{
			qx.delete() ;
			qy.delete() ;
		}
	}

	testMulQuaternionOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = new nkMaths.Quaternion () ;

		const rManaged = a.mulQuaternion(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.mulQuaternion_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testMulScalarOperator (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = 3 ;

		const ab = a.mulScalar(b) ;

		for (var i = 0 ; i < 4 ; ++i)
		{
			for (var j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(ab._m[i][j], a._m[i][j] * b, 0, "Incorrect mulScalar") ;
		}

		if (!managed)
			a.delete() ;
	}

	testMulScalarOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = 3 ;

		const rManaged = a.mulScalar(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.mulScalar_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	testDivScalarOperator (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor (1, 0, 0, 1, 0, 1, 0, 2, 0, 5, 1, 3, 0, 0, 0, 1) ;
		const b = 3 ;

		const ab = a.divScalar(b) ;

		for (var i = 0 ; i < 4 ; ++i)
		{
			for (var j = 0 ; j < 4 ; ++j)
				nkDebug.TestUtils.areNumbersEqual(ab._m[i][j], a._m[i][j] / b, 0.000001, "Incorrect divScalar") ;
		}

		if (!managed)
			a.delete() ;
	}

	testDivScalarOperatorDualReturns (managed)
	{
		const ctor = Matrix.instance.getMatrixConstructor(managed) ;
		const a = new ctor () ;
		const b = 3 ;

		const rManaged = a.divScalar(b) ;
		nkDebug.TestUtils.check(!nk.isUnmanagedInstance(rManaged), "Unmanaged should be managed") ;

		const rUnmanaged = a.divScalar_u(b) ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(rUnmanaged), "Managed should be unmanaged") ;
		rUnmanaged.delete() ;
		
		if (!managed)
			a.delete() ;
	}

	nkTests =
	{
		// Constructors
		DefaultConstructorUnmanaged : function ()
		{
			Matrix.instance.testDefaultConstructor(false) ;
		},
		DefaultConstructorManaged : function ()
		{
			Matrix.instance.testDefaultConstructor(true) ;
		},
		ArgsConstructorUnmanaged : function ()
		{
			Matrix.instance.testArgsConstructor(false) ;
		},
		ArgsConstructorManaged : function ()
		{
			Matrix.instance.testArgsConstructor(true) ;
		},
		CopyConstructorUnmanaged : function ()
		{
			Matrix.instance.testCopyConstructor(false, false) ;
		},
		CopyConstructorUnmanagedManaged : function ()
		{
			Matrix.instance.testCopyConstructor(false, true) ;
		},
		CopyConstructorManagedUnmanaged : function ()
		{
			Matrix.instance.testCopyConstructor(true, false) ;
		},
		CopyConstructorManaged : function ()
		{
			Matrix.instance.testCopyConstructor(true, true) ;
		},

		// Getters
		GetRow0Unmanaged : function ()
		{
			Matrix.instance.testGetRow0(false) ;
		},
		GetRow0Managed : function ()
		{
			Matrix.instance.testGetRow0(true) ;
		},
		GetRow1Unmanaged : function ()
		{
			Matrix.instance.testGetRow1(false) ;
		},
		GetRow1Managed : function ()
		{
			Matrix.instance.testGetRow1(true) ;
		},
		GetRow2Unmanaged : function ()
		{
			Matrix.instance.testGetRow2(false) ;
		},
		GetRow2Managed : function ()
		{
			Matrix.instance.testGetRow2(true) ;
		},
		GetRow3Unmanaged : function ()
		{
			Matrix.instance.testGetRow3(false) ;
		},
		GetRow3Managed : function ()
		{
			Matrix.instance.testGetRow3(true) ;
		},
		GetCol0Unmanaged : function ()
		{
			Matrix.instance.testGetCol0(false) ;
		},
		GetCol0Managed : function ()
		{
			Matrix.instance.testGetCol0(true) ;
		},
		GetCol1Unmanaged : function ()
		{
			Matrix.instance.testGetCol1(false) ;
		},
		GetCol1Managed : function ()
		{
			Matrix.instance.testGetCol1(true) ;
		},
		GetCol2Unmanaged : function ()
		{
			Matrix.instance.testGetCol2(false) ;
		},
		GetCol2Managed : function ()
		{
			Matrix.instance.testGetCol2(true) ;
		},
		GetCol3Unmanaged : function ()
		{
			Matrix.instance.testGetCol3(false) ;
		},
		GetCol3Managed : function ()
		{
			Matrix.instance.testGetCol3(true) ;
		},

		// Alterations
		GetInverseMat2Unmanaged : function ()
		{
			Matrix.instance.testGetInverseMat2(false) ;
		},
		GetInverseMat2Managed : function ()
		{
			Matrix.instance.testGetInverseMat2(true) ;
		},
		GetInverseMat3Unmanaged : function ()
		{
			Matrix.instance.testGetInverseMat3(false) ;
		},
		GetInverseMat3Managed : function ()
		{
			Matrix.instance.testGetInverseMat3(true) ;
		},
		GetInverseMat4Unmanaged : function ()
		{
			Matrix.instance.testGetInverseMat4(false) ;
		},
		GetInverseMat4Managed : function ()
		{
			Matrix.instance.testGetInverseMat4(true) ;
		},
		GetTransposeUnmanaged : function ()
		{
			Matrix.instance.testGetTranspose(false) ;
		},
		GetTransposeManaged : function ()
		{
			Matrix.instance.testGetTranspose(true) ;
		},
		InverseMat2Unmanaged : function ()
		{
			Matrix.instance.testInverseMat2(false) ;
		},
		InverseMat2Managed : function ()
		{
			Matrix.instance.testInverseMat2(true) ;
		},
		InverseMat3Unmanaged : function ()
		{
			Matrix.instance.testInverseMat3(false) ;
		},
		InverseMat3Managed : function ()
		{
			Matrix.instance.testInverseMat3(true) ;
		},
		InverseMat4Unmanaged : function ()
		{
			Matrix.instance.testInverseMat4(false) ;
		},
		InverseMat4Managed : function ()
		{
			Matrix.instance.testInverseMat4(true) ;
		},
		TransposeUnmanaged : function ()
		{
			Matrix.instance.testTranspose(false) ;
		},
		TransposeManaged : function ()
		{
			Matrix.instance.testTranspose(true) ;
		},

		// Transformations
		GetPositionComponentUnmanaged : function ()
		{
			Matrix.instance.testGetPositionComponent(false) ;
		},
		GetPositionComponentManaged : function ()
		{
			Matrix.instance.testGetPositionComponent(true) ;
		},
		GetOrientationComponentUnmanaged : function ()
		{
			Matrix.instance.testGetOrientationComponent(false) ;
		},
		GetOrientationComponentManaged : function ()
		{
			Matrix.instance.testGetOrientationComponent(true) ;
		},
		GetScaleComponentUnmanaged : function ()
		{
			Matrix.instance.testGetScaleComponent(false) ;
		},
		GetScaleComponentManaged : function ()
		{
			Matrix.instance.testGetScaleComponent(true) ;
		},
		SetToViewMatrixDirectionUnmanaged : function ()
		{
			Matrix.instance.testSetToViewMatrixDirection(false) ;
		},
		SetToViewMatrixDirectionManaged : function ()
		{
			Matrix.instance.testSetToViewMatrixDirection(true) ;
		},
		SetToPerspectiveMatrixUnmanaged : function ()
		{
			Matrix.instance.testSetToPerspectiveMatrix(false) ;
		},
		SetToPerspectiveMatrixManaged : function ()
		{
			Matrix.instance.testSetToPerspectiveMatrix(true) ;
		},
		SetToOrthographicMatrixUnmanaged : function ()
		{
			Matrix.instance.testSetToOrthographicMatrix(false) ;
		},
		SetToOrthographicMatrixManaged : function ()
		{
			Matrix.instance.testSetToOrthographicMatrix(true) ;
		},
		SetPositionComponentUnmanaged : function ()
		{
			Matrix.instance.testSetPositionComponent(false) ;
		},
		SetPositionComponentManaged : function ()
		{
			Matrix.instance.testSetPositionComponent(true) ;
		},
		SetOrientationComponentUnmanaged : function ()
		{
			Matrix.instance.testSetOrientationComponent(false) ;
		},
		SetOrientationComponentManaged : function ()
		{
			Matrix.instance.testSetOrientationComponent(true) ;
		},
		SetScaleComponentUnmanaged : function ()
		{
			Matrix.instance.testSetScaleComponent(false) ;
		},
		SetScaleComponentManaged : function ()
		{
			Matrix.instance.testSetScaleComponent(true) ;
		},
		SetToTransformationUnmanaged : function ()
		{
			Matrix.instance.testSetToTransformation(false) ;
		},
		SetToTransformationManaged : function ()
		{
			Matrix.instance.testSetToTransformation(true) ;
		},

		// Utilities
		DeterminantMat2Unmanaged : function ()
		{
			Matrix.instance.testDeterminantMat2(false) ;
		},
		DeterminantMat2Managed : function ()
		{
			Matrix.instance.testDeterminantMat2(true) ;
		},
		DeterminantMat3Unmanaged : function ()
		{
			Matrix.instance.testDeterminantMat3(false) ;
		},
		DeterminantMat3Managed : function ()
		{
			Matrix.instance.testDeterminantMat3(true) ;
		},
		DeterminantMat4Unmanaged : function ()
		{
			Matrix.instance.testDeterminantMat4(false) ;
		},
		DeterminantMat4Managed : function ()
		{
			Matrix.instance.testDeterminantMat4(true) ;
		},
		TraceMat2Unmanaged : function ()
		{
			Matrix.instance.testTraceMat2(false) ;
		},
		TraceMat2Managed : function ()
		{
			Matrix.instance.testTraceMat2(true) ;
		},
		TraceMat3Unmanaged : function ()
		{
			Matrix.instance.testTraceMat3(false) ;
		},
		TraceMat3Managed : function ()
		{
			Matrix.instance.testTraceMat3(true) ;
		},
		TraceMat4Unmanaged : function ()
		{
			Matrix.instance.testTraceMat4(false) ;
		},
		TraceMat4Managed : function ()
		{
			Matrix.instance.testTraceMat4(true) ;
		},

		// Operators
		EqualsOperatorUnmanaged : function ()
		{
			Matrix.instance.testEqualsOperator(false, false) ;
		},
		EqualsOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testEqualsOperator(false, true) ;
		},
		EqualsOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testEqualsOperator(true, false) ;
		},
		EqualsOperatorManaged : function ()
		{
			Matrix.instance.testEqualsOperator(true, true) ;
		},
		AssignOperatorUnmanaged : function ()
		{
			Matrix.instance.testAssignOperator(false, false) ;
		},
		AssignOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testAssignOperator(false, true) ;
		},
		AssignOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testAssignOperator(true, false) ;
		},
		AssignOperatorManaged : function ()
		{
			Matrix.instance.testAssignOperator(true, true) ;
		},
		CloneOperatorUnmanaged : function ()
		{
			Matrix.instance.testCloneOperator(false) ;
		},
		CloneOperatorManaged : function ()
		{
			Matrix.instance.testCloneOperator(true) ;
		},
		AddOperatorUnmanaged : function ()
		{
			Matrix.instance.testAddOperator(false, false) ;
		},
		AddOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testAddOperator(false, true) ;
		},
		AddOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testAddOperator(true, false) ;
		},
		AddOperatorManaged : function ()
		{
			Matrix.instance.testAddOperator(true, true) ;
		},
		AddOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testAddOperatorDualReturns(false) ;
		},
		AddOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testAddOperatorDualReturns(true) ;
		},
		SubOperatorUnmanaged : function ()
		{
			Matrix.instance.testSubOperator(false, false) ;
		},
		SubOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testSubOperator(false, true) ;
		},
		SubOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testSubOperator(true, false) ;
		},
		SubOperatorManaged : function ()
		{
			Matrix.instance.testSubOperator(true, true) ;
		},
		SubOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testSubOperatorDualReturns(false) ;
		},
		SubOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testSubOperatorDualReturns(true) ;
		},
		MulOperatorUnmanaged : function ()
		{
			Matrix.instance.testMulOperator(false, false) ;
		},
		MulOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testMulOperator(false, true) ;
		},
		MulOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testMulOperator(true, false) ;
		},
		MulOperatorManaged : function ()
		{
			Matrix.instance.testMulOperator(true, true) ;
		},
		MulOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testMulOperatorDualReturns(false) ;
		},
		MulOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testMulOperatorDualReturns(true) ;
		},
		MulVectorOperatorUnmanaged : function ()
		{
			Matrix.instance.testMulVectorOperator(false, false) ;
		},
		MulVectorOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testMulVectorOperator(false, true) ;
		},
		MulVectorOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testMulVectorOperator(true, false) ;
		},
		MulVectorOperatorManaged : function ()
		{
			Matrix.instance.testMulVectorOperator(true, true) ;
		},
		MulVectorOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testMulVectorOperatorDualReturns(false) ;
		},
		MulVectorOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testMulVectorOperatorDualReturns(true) ;
		},
		MulQuaternionOperatorUnmanaged : function ()
		{
			Matrix.instance.testMulQuaternionOperator(false, false) ;
		},
		MulQuaternionOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testMulQuaternionOperator(false, true) ;
		},
		MulQuaternionOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testMulQuaternionOperator(true, false) ;
		},
		MulQuaternionOperatorManaged : function ()
		{
			Matrix.instance.testMulQuaternionOperator(true, true) ;
		},
		MulQuaternionOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testMulQuaternionOperatorDualReturns(false) ;
		},
		MulQuaternionOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testMulQuaternionOperatorDualReturns(true) ;
		},
		MulScalarOperatorUnmanaged : function ()
		{
			Matrix.instance.testMulScalarOperator(false, false) ;
		},
		MulScalarOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testMulScalarOperator(false, true) ;
		},
		MulScalarOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testMulScalarOperator(true, false) ;
		},
		MulScalarOperatorManaged : function ()
		{
			Matrix.instance.testMulScalarOperator(true, true) ;
		},
		MulScalarOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testMulScalarOperatorDualReturns(false) ;
		},
		MulScalarOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testMulScalarOperatorDualReturns(true) ;
		},
		DivScalarOperatorUnmanaged : function ()
		{
			Matrix.instance.testMulOperator(false, false) ;
		},
		DivScalarOperatorUnmanagedManaged : function ()
		{
			Matrix.instance.testDivScalarOperator(false, true) ;
		},
		DivScalarOperatorManagedUnmanaged : function ()
		{
			Matrix.instance.testDivScalarOperator(true, false) ;
		},
		DivScalarOperatorManaged : function ()
		{
			Matrix.instance.testDivScalarOperator(true, true) ;
		},
		DivScalarOperatorDualReturnsUnmanaged : function ()
		{
			Matrix.instance.testDivScalarOperatorDualReturns(false) ;
		},
		DivScalarOperatorDualReturnsManaged : function ()
		{
			Matrix.instance.testDivScalarOperatorDualReturns(true) ;
		},
	}
}